package com.derby.nuke.gradle.dependencymanagement;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.ObjectId;
import org.gradle.api.Project;
import org.gradle.api.file.FileCollection;
import org.gradle.api.plugins.BasePluginConvention;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.plugins.WarPlugin;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.bundling.Jar;
import org.gradle.api.tasks.bundling.War;

import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class PackageConfiguration {
    private static final String JAR_TASK = JavaPlugin.JAR_TASK_NAME;
    private static final String WAR_TASK = "war";
    private static final String SOURCES_TASK = "sources";
    private static final String PROP_PROJECT_NAME = DependencyManagementPlugin.PROP_PROJECT_NAME;

    private Project project;

    public PackageConfiguration(Project project) {
        this.project = project;
    }


    public void configure(BasePluginConvention convention) {
        configureJarTask(project, convention);
        createSourceArchiveTask(project, convention);


        if (project.getPlugins().hasPlugin("war")) {
            configureWarTask(project, convention);
        }
    }


    /**
     * "Built-By": grgit.head().author.name,
     * 'Created-By': "Derbysoft Nuke",
     * 'Implementation-Title': archivesBaseName,
     * "Implementation-Timestamp": new Date().format("yyyy-MM-dd HH:mm:ss"),
     * "Specification-Version": version,
     * "Implementation-Version": grgit.head().id,
     * "Implementation-Vendor": "nuke",
     * "SVN-Version": -1,
     * "Git-Commit": grgit.head().id,
     * "Git-Branch": grgit.branch.current().getName()
     *
     * @param project
     */
    private void configureJarTask(Project project, BasePluginConvention convention) {

        Map<String, String> gitAttrs = new HashMap<>();
        try {
            File buildDir = project.getRootProject().getRootDir();
            if (!new File(buildDir, ".git").exists()) {
                throw new IllegalStateException("Not a git dir.");
            }

            Git git = Git.open(buildDir);

            String branch = git.getRepository().getBranch();
            ObjectId head = git.getRepository().resolve("HEAD");
            String name = git.getRepository().parseCommit(head).getCommitterIdent().getName();


            gitAttrs.put("Git-Branch", branch);
            gitAttrs.put("Git-Commit", head.name());
            gitAttrs.put("Built-By", name);
            gitAttrs.put("Implementation-Version", head.name());


        } catch (Exception e) {
            project.getLogger().warn("Get git[{}] Attributes fail.:", project.getProjectDir(), e);
        }


        project.getTasks().withType(Jar.class).named(JAR_TASK).configure(jarTask -> {
            project.getLogger().info("config jar:" + jarTask.getEnabled());

            Map<String, String> attr = new HashMap<>(gitAttrs);
            attr.put("Created-By", "Derbysoft Nuke");
            attr.put("Implementation-Timestamp", new Date().toString());
            attr.put("Specification-Version", project.getVersion().toString());
            attr.put("Implementation-Vendor", "Nuke");
            attr.put("SVN-Version", "-1");

            jarTask.setEnabled(true);
            jarTask.getManifest().attributes(attr);

            jarTask.setArchiveName(getProjectName(project) + ".jar");
        });
    }


    private void configureWarTask(Project project, BasePluginConvention convention) {

        Jar jarTask = (Jar) project.getTasks().getByName(JAR_TASK);
        Jar sourceTask = (Jar) project.getTasks().getByName(SOURCES_TASK);
        JavaPluginConvention javaPluginConvention = project.getConvention().getPlugin(JavaPluginConvention.class);

        project.getTasks().withType(War.class).named(WAR_TASK).configure(warTask -> {
            project.getLogger().info("config war:" + warTask.getEnabled());

            warTask.setEnabled(true);
            warTask.dependsOn(jarTask, sourceTask);

            FileCollection classPath =
                    warTask.getClasspath()
                            .plus(jarTask.getOutputs().getFiles())
                            .minus(javaPluginConvention.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME).getOutput());

            warTask.setClasspath(classPath);
            warTask.setArchiveName(getProjectName(project) + ".war");
        });
    }

    private void createSourceArchiveTask(Project project, BasePluginConvention convention) {
        JavaPluginConvention javaConvention = project.getConvention().getPlugin(JavaPluginConvention.class);

        project.getTasks().create(SOURCES_TASK, Jar.class, jar -> {
            jar.dependsOn(JavaPlugin.CLASSES_TASK_NAME);
            jar.setArchiveName(getProjectName(project) + "-sources.jar");
            jar.from(javaConvention.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME).getAllSource());
        });

    }


    private String getProjectName(Project project) {
        return project.getExtensions().getExtraProperties().get(PROP_PROJECT_NAME).toString();
    }


}
